package cn.sdormitory.workflow.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.sdormitory.basedata.dao.BClassDao;
import cn.sdormitory.basedata.dao.BStudentDao;
import cn.sdormitory.basedata.entity.BClass;
import cn.sdormitory.basedata.entity.BStudent;
import cn.sdormitory.common.utils.SysUserUtils;
import cn.sdormitory.sys.dao.SysDeptDao;
import cn.sdormitory.sys.dao.SysUserDao;
import cn.sdormitory.sys.entity.SysDept;
import cn.sdormitory.sys.entity.SysUser;
import cn.sdormitory.workflow.dao.ViolationApplyDao;
import cn.sdormitory.workflow.entity.StudentsViolationApply;
import cn.sdormitory.workflow.entity.ViolationApply;
import cn.sdormitory.workflow.service.ViolationApplyService;
import cn.sdormitory.workflow.service.WorkFlowCommonService;
import cn.sdormitory.workflow.vo.WorkFlowVO;
import cn.sdormitory.wx.entity.WechatPushMessage;
import cn.sdormitory.wx.mapper.WechatPushMessageMapper;
import cn.sdormitory.wx.utils.WXUtil;
import cn.sdormitory.wx.utils.WeatherDataCreator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.activiti.engine.HistoryService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class ViolationApplyServiceImpl extends ServiceImpl<ViolationApplyDao, ViolationApply> implements ViolationApplyService {

    @Resource
    WorkFlowCommonService workFlowCommonService;
    @Resource
    BStudentDao bStudentDao;

    @Resource
    BClassDao bClassDao;

    @Resource
    SysUserDao sysUserDao;
    @Resource
    SysDeptDao SysDeptDao;
    @Autowired
    private HistoryService historyService;
    
    @Resource
    private WeatherDataCreator weatherDataCreator;
    
    @Resource
    private WXUtil wxUtil;
    
    @Resource
    private WechatPushMessageMapper wechatPushMessageMapper;
    
    private static final String VIOLATION_PUSH_TEMPLATEID = "embMMz-4Swbohiid3q8FlIRxd4ejQ4SxLPWfnGvjQtc";
    /**
     * 查询自己创建的申请单
     * @param apply
     * @return
     */
    @Override
    public IPage<ViolationApply> pageList(ViolationApply apply) {
        IPage<ViolationApply> page = new Page<>(apply.getPageNum(), apply.getPageSize());
        String username = SysUserUtils.getSysUser().getUsername();
        //发起人
        if("1".equals(apply.getType())){
            apply.setCreateBy(apply.getCreateBy());
            apply.setApplyStatus("1");
        }
        if("2".equals(apply.getType())){
            apply.setCurrentApprover(apply.getCreateBy());
        }
        return this.baseMapper.getApplyPage(apply,page);
    }
    
    @Override
    public IPage<ViolationApply> getProcessedPageList(ViolationApply apply) {
        IPage<ViolationApply> page = new Page<>(apply.getPageNum(), apply.getPageSize());
        apply.setApplyStatus("10");
        return this.baseMapper.getApplyPage(apply,page);
    }
    
    /**
     * 创建申请单
     * @param apply
     * @return
     */
    @Override
    public int createApply(List<StudentsViolationApply> applyList) {
        String username = SysUserUtils.getSysUser().getUsername();
        List<ViolationApply> violationApplies = new ArrayList<>();
        for (StudentsViolationApply studentsViolationApply : applyList) {
            ViolationApply apply = new ViolationApply();
            BeanUtil.copyProperties(studentsViolationApply, apply);
            if(StringUtils.isEmpty(username)){
                //createBys实际为当前登录用户
                username = studentsViolationApply.getCreateBy();
            }
            //记录违纪，并启动处理流程
            String applyNo = DateUtil.format(new Date(),"yyyyMMddHHmmssSSS");
            //获取到班主任ID
            BStudent bStudent = bStudentDao.getStudentById(studentsViolationApply.getId().intValue());
            BClass bClass = bClassDao.selectById(bStudent.getClassId());
            Long approve = bClass.getClassTeacherId();
            SysUser sysUser = sysUserDao.selectById(approve);
            apply.setClassTeacherWxOpenId(sysUser.getWxOpenId());
            WorkFlowVO flowVO = new WorkFlowVO();
            flowVO.setApplyTitle("宿舍违纪处理流程");
            flowVO.setApplyID(apply.getApplyId());
            flowVO.setBusinessKey("SV-"+applyNo);
            //查询下级处理人
            Map<String,Object> map =new HashMap<>();
            map.put("assignee",sysUser.getUsername());
            flowVO.setVariables(map);
            //创建请假工作流
            String processInstanceId = workFlowCommonService.createProcessInstance(flowVO);
            apply.setProcessInstanceId(processInstanceId);
            //更新流程实例ID
            apply.setClassId(String.valueOf(bStudent.getClassId()));
            apply.setSdId(String.valueOf(bStudent.getBdormitoryId()));
            apply.setStudentId(String.valueOf(studentsViolationApply.getId()));
            apply.setStudentName(bStudent.getStudentName());
            apply.setClassName(bClass.getClassName());
            apply.setApplyNo("SV-"+applyNo);
            apply.setCreateTime(new Date());
            apply.setViolationReason(studentsViolationApply.getViolationReason());
            apply.setStudentImg(bStudent.getStuPhoto());
            if(!StringUtils.isEmpty(username)){
                apply.setCreateBy(username);
            }
            apply.setApplyStatus("1");//默认是审批中
            violationApplies.add(apply);
        }
        boolean saveBatch = saveBatch(violationApplies);
        if (saveBatch) {
            for (ViolationApply violationApply : violationApplies) {
                if (Objects.isNull(violationApply.getClassTeacherWxOpenId())) {
                    continue;
                }
                // 给班主任推送消息
                //消息封装
                Map<String, Object> weatherDataMap = weatherDataCreator.createViolationsDataMap(violationApply.getStudentName(), DateUtil.formatDateTime(violationApply.getCreateTime()));
    
                WechatPushMessage wechatPushMessage = new WechatPushMessage();
                wechatPushMessage.setTemplateId(VIOLATION_PUSH_TEMPLATEID);
                wechatPushMessage.setContent(weatherDataMap.toString());
                wechatPushMessage.setReceiverOpenId(violationApply.getClassTeacherWxOpenId());
                try {
                    JSONObject jsonObject = wxUtil.sendInfo(violationApply.getClassTeacherWxOpenId(), VIOLATION_PUSH_TEMPLATEID
                            , weatherDataMap,"");
                    wechatPushMessage.setStatus(true);
                    wechatPushMessage.setBackInfo(jsonObject.get("errmsg").toString());
                }catch (Exception e) {
                    System.out.println(e.getMessage());
                    wechatPushMessage.setStatus(false);
                    wechatPushMessage.setBackInfo(e.getMessage());
                }
                wechatPushMessageMapper.insert(wechatPushMessage);
            }
         
            return 1;
        }
        return 0;
    }

    /**
     * 撤销申请单
     * @param apply
     * @return
     */
    @Override
    public Boolean revokeApply(ViolationApply apply) {
        LambdaQueryWrapper<ViolationApply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ViolationApply::getProcessInstanceId,apply.getProcessInstanceId());
        ViolationApply applyVO = new ViolationApply();
        applyVO.setApplyStatus("2");//撤销流程
        applyVO.setModifyBy(SysUserUtils.getSysUser().getUsername());
        applyVO.setModifyTime(new Date());
        this.baseMapper.update(applyVO,wrapper);
        return workFlowCommonService.cancelApply(apply.getProcessInstanceId(),"");
    }
    
    @Override
    public List<ViolationApply> getViolationStatisticsDetail(String startDate, String endDate, String sdId) {
        List<ViolationApply> violationStatistics = this.baseMapper.getViolationStatistics(startDate, endDate, sdId);
        return violationStatistics;
    }
    
    @Override
    public List<Map<String, String>> getViolationStatistics(String startDate, String endDate) {
        List<ViolationApply> violationStatistics = this.baseMapper.getViolationStatistics(startDate, endDate, null);
        Map<String, List<ViolationApply>> collect = violationStatistics.stream().collect(Collectors.groupingBy(ViolationApply::getSdId));
        
        List<Map<String, String>> resultList = new ArrayList<>();
        for (Map.Entry<String, List<ViolationApply>> listEntry : collect.entrySet()) {
            Map<String, String> resulrMap = new HashMap<>();
            String sdId = listEntry.getKey();
            List<ViolationApply> entryValue = listEntry.getValue();
            resulrMap.put("sdId", sdId);
            resulrMap.put("dormitoryNo", entryValue.get(0).getDormitoryNo());
            resulrMap.put("buildingNo", entryValue.get(0).getBuildingNo());
            resulrMap.put("buildingName", Integer.parseInt(entryValue.get(0).getBuildingNo()) == 1 ? "畔湖苑" : "听湖苑");
            resulrMap.put("violationCount", String.valueOf(entryValue.size()));
            resultList.add(resulrMap);
        }
        
        return resultList;
    }
    
    @Override
    public ViolationApply applyDetail(ViolationApply apply) {
        LambdaQueryWrapper<ViolationApply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ViolationApply::getId,apply.getId());
        return this.baseMapper.selectOne(wrapper);
    }

    /**
     * 查询审批历史
     * @param vo
     * @return
     */
    @Override
    public IPage<ViolationApply> findHistoryApproval(WorkFlowVO vo) {
        String username = SysUserUtils.getSysUser().getUsername();
        if(StringUtils.isEmpty(username)){
            username = vo.getCreateBy();
        }
        int startNum=(vo.getPageNum()-1)*vo.getPageSize();
        List<HistoricTaskInstance> hisTaskList = historyService.createHistoricTaskInstanceQuery().finished()
                .taskInvolvedUser(username)
                .processDefinitionKey(vo.getApplyID())
                .orderByTaskCreateTime().desc().listPage(startNum,vo.getPageSize());
        Long count = historyService.createHistoricTaskInstanceQuery().finished().taskInvolvedUser(username)
                .processDefinitionKey(vo.getApplyID()).count();
        List<WorkFlowVO> leaveTasks = new ArrayList<>();
        for (HistoricTaskInstance task : hisTaskList) {
//            List<HistoricTaskInstance> hTask = historyService.createHistoricTaskInstanceQuery()
//                    .processDefinitionKey(task.getProcessDefinitionKey()).taskAssignee(username).list();
            WorkFlowVO flowVO = new WorkFlowVO();
            flowVO.setTaskId(task.getId());
            flowVO.setName(task.getName());
//            LambdaQueryWrapper<ViolationApply> wrapper = new LambdaQueryWrapper<>();
//            wrapper.eq(ViolationApply::getProcessInstanceId,task.getProcessInstanceId());
            ViolationApply violationApply = this.baseMapper.getByProcessInstanceId(task.getProcessInstanceId());
            flowVO.setBusinessData(violationApply);
            flowVO.setProcessInstanceId(task.getProcessInstanceId());
            flowVO.setProcessDefinitionId(task.getProcessDefinitionId());
            flowVO.setCreateTime(task.getStartTime());
            leaveTasks.add(flowVO);
        }
        IPage ipage = new Page();
        ipage.setTotal(count);
        ipage.setRecords(leaveTasks);
        return ipage;
    }

    /**
     * 设置流程审批人
     * @param vo 流程对象
     */
    @Override
    public void setApprover(WorkFlowVO vo) {
        LambdaQueryWrapper<ViolationApply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ViolationApply::getProcessInstanceId, vo.getProcessInstanceId());
        ViolationApply violationApply = this.baseMapper.selectOne(wrapper);
        Map<String,Object> map = new HashMap<>();
        if(vo.getCurrNode().startsWith("classTeacherHandle")){
            if(0 == vo.getFlag()){
                //班主任不能处理，设置下级审批人提交给部门经理
                String username = teacherId(violationApply.getClassId());
                String assignee = getDeptManager(username).getLeader();
                map.put("assignee",assignee);
                vo.setVariables(map);
            }
        }
        if(vo.getCurrNode().startsWith("deptManageHandle")){
            if(0 == vo.getFlag()){
                //部门经理不能处理，设置下级审批人提交给政教处
                String assignee = teachPerson().getLeader();
                map.put("assignee",assignee);
                vo.setVariables(map);
            }
        }
    }

    @Override
    public void processResult(WorkFlowVO vo) {
        LambdaQueryWrapper<ViolationApply> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ViolationApply::getProcessInstanceId, vo.getProcessInstanceId());
        ViolationApply violationApply = this.baseMapper.selectOne(wrapper);
        if(vo.getCurrNode().startsWith("classTeacherHandle")){
            if(1 == vo.getFlag()){
                //班主任处理完成
                violationApply.setApplyStatus("10");
                violationApply.setResultFilePath(vo.getAttachment());
                violationApply.setProcessResult(vo.getApplyDesc());
                this.baseMapper.updateById(violationApply);
            }
        }
        if(vo.getCurrNode().startsWith("deptManageHandle")){
            if(1 == vo.getFlag()){
                //部门经理处理完成
                violationApply.setApplyStatus("10");
                violationApply.setResultFilePath(vo.getAttachment());
                violationApply.setProcessResult(vo.getApplyDesc());
                this.baseMapper.updateById(violationApply);
            }
        }
        if(vo.getCurrNode().startsWith("teachHandle")){
            if(1 == vo.getFlag()){
                //政教处处理完成
                violationApply.setApplyStatus("10");
                violationApply.setResultFilePath(vo.getAttachment());
                violationApply.setProcessResult(vo.getApplyDesc());
                this.baseMapper.updateById(violationApply);
            }
        }
    }

    /**
     * 查询班主任
     * @param classId
     * @return
     */
    private String teacherId(String classId){
        BClass bClass = bClassDao.selectById(classId);
        Long approve = bClass.getClassTeacherId();
        SysUser sysUser = sysUserDao.selectById(approve);
        return sysUser.getUsername();
    }
    /**
     * 查询政教处审批人
     * @return
     */
    private SysDept teachPerson(){
        LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDept::getName,"政教处");
        SysDept sysDept = this.SysDeptDao.selectOne(wrapper);
        return sysDept;
    }
    /**
     * 查询部门经理审批人
     * @return
     */
    private SysDept getDeptManager(String userName){
        LambdaQueryWrapper<SysUser> userWrapper = new LambdaQueryWrapper<>();
        userWrapper.eq(SysUser::getUsername,userName);
        SysUser sysUser = sysUserDao.selectOne(userWrapper);

        LambdaQueryWrapper<SysDept> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(SysDept::getId,sysUser.getDeptId());
        SysDept sysDept = this.SysDeptDao.selectOne(wrapper);
        return sysDept;
    }
}
